package com.redissdk.redis;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.redissdk.redis.common.ms.JedisClusterPool;

import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.util.Pool;

/**
  * 项目名称:[redisx]
  * 包:[com.redissdk.redis]    
  * 文件名称:[RedisClusterUtils]  
  * 描述:[一句话描述该文件的作用]
  * 创建人:[彭小林]
  * 创建时间:[2017年1月3日 下午5:49:13]   
  * 修改人:[彭小林]   
  * 修改时间:[2017年1月3日 下午5:49:13]   
  * 修改备注:[说明本次修改内容]  
  * 版权所有:luwenbin006@163.com
  * 版本:[v1.0]
 */
public class RedisClusterUtils {

	protected static Logger logger = Logger.getLogger(RedisMasterSlaveUtil.class);

	private static List<String> hostAndPorts;

	// 可用连接实例的最大数目，默认值为8；
	// 如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
	private static int MAX_ACTIVE = 0;

	// 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8。
	private static int MAX_IDLE = 0;

	// 等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出JedisConnectionException；
	private static int MAX_WAIT = 0;

	// 超时时间
	private static int TIMEOUT = 0;

	private static int maxRedirections;

	// 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
	private static boolean TEST_ON_BORROW = false;

	private static Pool<JedisCluster> jedisClusterPool = null;

	private static String configPath="properties/redis_cluster.properties";
	

	/**
	 * 初始化Redis连接池
	 */
	private static void initialPool() {

		initRedisConfigValue();
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxTotal(MAX_ACTIVE);
		config.setMaxIdle(MAX_IDLE);
		config.setMaxWaitMillis(MAX_WAIT);
		config.setTestOnBorrow(TEST_ON_BORROW);
		jedisClusterPool = new JedisClusterPool(hostAndPorts, maxRedirections, config, TIMEOUT);

	}

	private static void initRedisConfigValue() {

		// TODO Auto-generated method stub
		// master_server=192.168.1.16
		// master_port=6380
		String _clusterNodes = FileUtil.getPropertyValue(configPath, "clusterNodes");
		hostAndPorts = new LinkedList<String>();

		if (!StringUtils.isEmpty(_clusterNodes)) {
			String[] address = _clusterNodes.split(",");
			for (String add : address) {
				hostAndPorts.add(add);
			}
		}

		maxRedirections = FileUtil.getPropertyValueInt(configPath, "maxRedirections");

		MAX_ACTIVE = FileUtil.getPropertyValueInt(configPath, "max_active");

		MAX_IDLE = FileUtil.getPropertyValueInt(configPath, "max_idle");

		MAX_WAIT = FileUtil.getPropertyValueInt(configPath, "max_wait");

		TIMEOUT = FileUtil.getPropertyValueInt(configPath, "timeout");

		TEST_ON_BORROW = FileUtil.getPropertyValueBoolean(configPath, "test_on_borrow");

		FileUtil.remove(configPath);
	}

	/**
	 * 在多线程环境同步初始化
	 */
	private static synchronized void poolInit() {
		if (jedisClusterPool == null) {
			initialPool();
		}
	}

	/**
	 * 同步获取Jedis实例
	 * 
	 * @return Jedis
	 */
	private synchronized static JedisCluster getJedisCluster() {
		if (jedisClusterPool == null) {
			poolInit();
		}
		JedisCluster jedis = null;
		try {
			if (jedisClusterPool != null) {
				jedis = jedisClusterPool.getResource();
			}
		} catch (Exception e) {
			returnResource(jedis);
			logger.error("Get jedis error : " + e);
		}

		return jedis;
	}

	/**
	 * 释放jedis资源
	 * 
	 * @param jedis
	 */
	public static void returnResource(final JedisCluster jedis) {
		if (jedis != null && null != jedisClusterPool) {
			jedisClusterPool.returnResource(jedis);
		}
	}

	/**
	 * 设置 String
	 * 
	 * @param key
	 * @param value
	 */
	public static String setString(String key, String value) {
		JedisCluster jedisCluster = null;
		String r_str = "nil";
		try {
			value = StringUtils.isEmpty(value) ? "" : value;
			jedisCluster = getJedisCluster();
			r_str = jedisCluster.set(key, value);
		} catch (Exception e) {
			logger.error("Set key error : " + e);
		} finally {
			returnResource(jedisCluster);
		}

		return r_str;
	}

	/**
	 * 设置 过期时间
	 * 
	 * @param key
	 * @param seconds
	 *            以秒为单位
	 * @param value
	 */
	public static String setString(String key, String value, int expirationTime) {
		JedisCluster jedisCluster = null;
		String r_str = "nil";
		try {
			value = StringUtils.isEmpty(value) ? "" : value;
			jedisCluster = getJedisCluster();
			r_str = jedisCluster.setex(key, expirationTime, value);
		} catch (Exception e) {
			logger.error("Set keyex error : " + e);
		} finally {
			returnResource(jedisCluster);
		}

		return r_str;
	}

	public static Set<byte[]> getKeys(byte[] keys) {
		JedisCluster jedisCluster = getJedisCluster();
		Set<byte[]> set_ = jedisCluster.hkeys(keys);
		returnResource(jedisCluster);
		return set_;
	}

	public static Set<String> getKeys(String keys) {
		JedisCluster jedisCluster = getJedisCluster();
		Set<String> set_ = jedisCluster.hkeys(keys);
		returnResource(jedisCluster);
		return set_;
	}

	public static Set<byte[]> hkeys(byte[] hkeys) {
		JedisCluster jedisCluster = getJedisCluster();
		Set<byte[]> set_ = jedisCluster.hkeys(hkeys);
		returnResource(jedisCluster);
		return set_;
	}

	public static Set<String> hkeys(String hkeys) {
		JedisCluster jedisCluster = getJedisCluster();
		Set<String> set_ = jedisCluster.hkeys(hkeys);
		returnResource(jedisCluster);
		return set_;

	}

	public static Collection<byte[]> hvals(byte[] hvals) {
		JedisCluster jedisCluster = getJedisCluster();
		Collection<byte[]> collection = jedisCluster.hvals(hvals);
		returnResource(jedisCluster);
		return collection;
	}

	public static List<String> hvals(String hvals) {
		JedisCluster jedisCluster = getJedisCluster();
		List<String> list = jedisCluster.hvals(hvals);
		returnResource(jedisCluster);
		return list;
	}

	/**
	 * 获取String值
	 * 
	 * @param key
	 * @return value
	 */
	public static String getString(String key) {
		JedisCluster jedisCluster = getJedisCluster();
		String r_str = null;
		if (jedisCluster == null || !jedisCluster.exists(key)) {
			r_str = null;
			if (null != jedisCluster) {
				returnResource(jedisCluster);
			}
		} else {
			r_str = jedisCluster.get(key);
		}
		returnResource(jedisCluster);
		return r_str;
	}

	public static String setObject(String key, Object obj, int expirationTime) {
		String r_str = null;

		if (null == obj) {
			r_str = "nil";
		} else {
			JedisCluster jedisCluster = null;
			try {
				jedisCluster = getJedisCluster();
				r_str = jedisCluster.setex(key.getBytes(), expirationTime,
						SerializationAndCompressUtils.fastSerialize(obj));

			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {

				returnResource(jedisCluster);

			}
		}

		return r_str;

	}

	public static String setObject(String key, Object obj) {
		String r_str = null;

		if (null == obj) {
			r_str = "nil";
		} else {
			JedisCluster jedisCluster = null;
			try {

				jedisCluster = getJedisCluster();
				r_str = jedisCluster.set(key.getBytes(), SerializationAndCompressUtils.fastSerialize(obj));

			} catch (Exception e) {
				// return jedis object to pll and set jedis is null.
				returnResource(jedisCluster);
				jedisCluster = null;
				e.printStackTrace();
			} finally {

				returnResource(jedisCluster);

			}
		}

		return r_str;

	}

	public static Long del(String key) {
		Long r_l = 0l;
		JedisCluster jedisCluster = null;
		try {
			jedisCluster = getJedisCluster();
			r_l = jedisCluster.del(key);

		} catch (Exception e) {
			// return jedis object to pll and set jedis is null.
			returnResource(jedisCluster);
			jedisCluster = null;
			e.printStackTrace();
		} finally {

			returnResource(jedisCluster);

		}
		return r_l;

	}

	public static Long del(byte[] key) {
		Long r_l = 0l;
		JedisCluster jedisCluster = null;
		try {
			jedisCluster = getJedisCluster();
			r_l = jedisCluster.del(key);

		} catch (Exception e) {
			// return jedis object to pll and set jedis is null.
			returnResource(jedisCluster);
			jedisCluster = null;
			e.printStackTrace();
		} finally {

			returnResource(jedisCluster);

		}
		return r_l;

	}

	/**
	 * 获取Object
	 * 
	 * @param key
	 * @return
	 * @return value
	 */
	public static <T> T getObject(String key, Class<T> classz) {
		JedisCluster jedisCluster = getJedisCluster();

		T t = null;

		if (jedisCluster == null || !jedisCluster.exists(key.getBytes())) {
			t = null;
			if (null != jedisCluster) {
				returnResource(jedisCluster);
			}
		} else {
			byte[] value = jedisCluster.get(key.getBytes());
			try {

				if (null == value) {
					t = null;
				} else {
					t = classz.cast(SerializationAndCompressUtils.fastDeserialize(value));
				}
			} catch (Exception e) {
				// return jedis object to pll and set jedis is null.
				returnResource(jedisCluster);
				jedisCluster = null;
				e.printStackTrace();
			} finally {

				returnResource(jedisCluster);

			}
		}

		return t;
	}

	public static Long hdel(String key, String field) {
		JedisCluster jedisCluster = getJedisCluster();
		Long r_l = 0l;
		if (jedisCluster == null) {
			r_l = 0l;
		} else {
			try {
				r_l = jedisCluster.hdel(key, field);
			} catch (Exception e) {
				// return jedis object to pll and set jedis is null.
				returnResource(jedisCluster);
				jedisCluster = null;
				e.printStackTrace();
			} finally {

				returnResource(jedisCluster);

			}
		}
		return r_l;
	}

	public static Map<String, String> hgetall(String key) {
		JedisCluster jedisCluster = getJedisCluster();
		Map<String, String> map = null;
		if (jedisCluster == null) {
			map = null;
		} else {
			try {

				map = jedisCluster.hgetAll(key);

			} catch (Exception e) {
				// return jedis object to pll and set jedis is null.
				returnResource(jedisCluster);
				jedisCluster = null;
				e.printStackTrace();
			} finally {

				returnResource(jedisCluster);

			}
		}

		return map;
	}

	public static Long hincrBy(String key, String field, long value) {
		JedisCluster jedisCluster = getJedisCluster();
		Long r_l = 0l;
		if (jedisCluster == null) {
			r_l = 0l;
		} else {
			try {
				r_l = jedisCluster.hincrBy(key, field, value);
			} catch (Exception e) {
				// return jedis object to pll and set jedis is null.
				returnResource(jedisCluster);
				jedisCluster = null;
				e.printStackTrace();
			} finally {

				returnResource(jedisCluster);

			}
		}

		return r_l;
	}

}
